package oleg.lcdui;

/**
 * Copyright 2008 Oleg Frenkel
 *
 * This file is part of PerfectSearch.
 *
 * PerfectSearch is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * PerfectSearch is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with PerfectSearch.  If not, see <http://www.gnu.org/licenses/>.
 */

import javax.microedition.lcdui.*;
import java.util.*;

import oleg.C;

public class InputTextProcessor
{
  private int padMode = C.PAD_MODE_PRED_ON;

  // Let give half a second for a user to enter next char
  private final static long MAX_CHAR_PERIOD = 1000;

  private Vector predictionAllowedStrings;
  private StringBuffer inputTextSB;

  // Time when last key was entered
  private long timeLastKeyEntered = -1;
  // which keyCode was entered last time
  private long lastKeyCode = -1;
  // index of a char that was used last time (second index in chars array)
  private int nextCharIndex = 0;

  private String[][] chars = new String[][] 
    {
      {"0"},
      {"1"}, 
      {"A", "B", "C", "2"},
      {"D", "E", "F", "3"},
      {"G", "H", "I", "4"},
      {"J", "K", "L", "5"},
      {"M", "N", "O", "6"},
      {"P", "Q", "R", "S", "7"},
      {"T", "U", "V", "8"},
      {"W", "X", "Y", "Z", "9"},
      {"*", "-", "+", ",", ".", "!", "?"}, 
      {"#"}
    };
  private Hashtable keyCode2charsIndex = new Hashtable();

  public InputTextProcessor(StringBuffer inputTextSB) {
    this.inputTextSB = inputTextSB;

    keyCode2charsIndex.put(new Integer(Canvas.KEY_NUM0), new Integer(0));
    keyCode2charsIndex.put(new Integer(Canvas.KEY_NUM1), new Integer(1));
    keyCode2charsIndex.put(new Integer(Canvas.KEY_NUM2), new Integer(2));
    keyCode2charsIndex.put(new Integer(Canvas.KEY_NUM3), new Integer(3));
    keyCode2charsIndex.put(new Integer(Canvas.KEY_NUM4), new Integer(4));
    keyCode2charsIndex.put(new Integer(Canvas.KEY_NUM5), new Integer(5));
    keyCode2charsIndex.put(new Integer(Canvas.KEY_NUM6), new Integer(6));
    keyCode2charsIndex.put(new Integer(Canvas.KEY_NUM7), new Integer(7));
    keyCode2charsIndex.put(new Integer(Canvas.KEY_NUM8), new Integer(8));
    keyCode2charsIndex.put(new Integer(Canvas.KEY_NUM9), new Integer(9));
    keyCode2charsIndex.put(new Integer(Canvas.KEY_STAR), new Integer(10));
    keyCode2charsIndex.put(new Integer(Canvas.KEY_POUND), new Integer(11));

    predictionAllowedStrings = new Vector();
    predictionAllowedStrings.addElement("2");
    predictionAllowedStrings.addElement("3");
    predictionAllowedStrings.addElement("4");
    predictionAllowedStrings.addElement("5");
    predictionAllowedStrings.addElement("6");
    predictionAllowedStrings.addElement("7");
    predictionAllowedStrings.addElement("8");
    predictionAllowedStrings.addElement("9");
  }

  public long getLastTimeKeyEntered() {
    return timeLastKeyEntered;
  }

  public void setPadMode(int padMode) {
    this.padMode = padMode;
  }

  public int getPadMode() {
    return padMode;
  }

  public void processKey(int keyCode) {
    Integer charIndInt = (Integer)keyCode2charsIndex.get(new Integer(keyCode));
    if (charIndInt == null) {
      // key that we do not process
      return;
    }

    int charInd = charIndInt.intValue();
    
//     System.out.println("here: padMode: " + padMode +
//                        " charInd: " + charInd); 

    // Either pad mode is abc or user pressed non-numerical key
    if (padMode == C.PAD_MODE_PRED_OFF) {
      long currentTime = System.currentTimeMillis();
      if (chars[charInd].length == 1 ||
          currentTime - timeLastKeyEntered > MAX_CHAR_PERIOD ||
          lastKeyCode != keyCode) {
        startNewSequence(keyCode, charInd);
        return;
      }
      
      continueSequence(keyCode, charInd);
    } else if (padMode == C.PAD_MODE_NUM) {
      // pad is numerical
      // Digit is the last item in the array
      if (charInd >= 10) {
        return;
      }

      String ch = chars[charInd][chars[charInd].length - 1];
      inputTextSB.append(ch);
    } else {
      // pad is prediction on
      // Digit is the last item in the array
      if (charInd >= 10) {
        return;
      }

      String ch = chars[charInd][chars[charInd].length - 1];
      if (predictionAllowedStrings.contains(ch)) {
        inputTextSB.append(ch);
      }
    }
  }

  private void startNewSequence(int keyCode, int charInd) {
    String ch = chars[charInd][0];
    inputTextSB.append(ch);
    timeLastKeyEntered = System.currentTimeMillis();
    lastKeyCode = keyCode;
    nextCharIndex = 1 % chars[charInd].length;
  }

  private void continueSequence(int keyCode, int charInd) {
    String ch = chars[charInd][nextCharIndex];
    // Replace last char
    inputTextSB.deleteCharAt(inputTextSB.length() - 1);
    inputTextSB.append(ch);
    timeLastKeyEntered = System.currentTimeMillis();
    lastKeyCode = keyCode;
    nextCharIndex = (nextCharIndex + 1) % chars[charInd].length;
  }
}
